﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Vibz.Game.Bugs.Model;
using System.Xml.Serialization;
using System.Xml;
using System.IO;
using Vibz.Common.Channel;
using Vibz.Common;
using System.Drawing;
using Vibz.Common.Model;
using Vibz.Common.Notification;

namespace Vibz.Game.Bugs.Model
{
    public class GroundManager : ModelManager
    {
        Random rnd = new Random();
        int groundIndex = 0;
        int ObjectThickness = 10;
        public GroundManager()
            : this(500, 500, 15)
        { }
        public GroundManager(string gndLength, string gndWidth, string objThickness)
            : this(int.Parse(gndLength), int.Parse(gndWidth), int.Parse(objThickness))
        { }
        public GroundManager(int gndLength, int gndWidth, int objThickness)
            : this(new Ground(gndLength, gndWidth), objThickness)
        {
        }
        public GroundManager(Ground gnd, int objThickness)
        {
            ObjectThickness = objThickness;
            Model = gnd;
            for (int i = 0; i < 5; i++)
            {
                AddCoin();
            }

            for (int i = 0; i < 5; i++)
            {
                AddObstacle();
            }

            for (int i = 0; i < 10; i++)
            {
                AddCompartment();
            }
            gnd.ValueChanged += new Common.Notification.ValueChangedEventHandler(gnd_ValueChanged);
        }

        void gnd_ValueChanged(object sender, Common.Notification.ValueChangedEventArgs e)
        {
            // Inform Server
        }

        PowerType GetRandomPowerType()
        {
            int iRnd = rnd.Next(0, Enum.GetNames(typeof(PowerType)).Length);
            return (PowerType)(Enum.GetValues(typeof(PowerType)).GetValue(iRnd));
        }

        public override void CreateClient(string endPoint)
        {
            AddPlayer(endPoint);
            base.Clear();
        }

        Player AddPlayer(string endPoint)
        {
            ((Ground)Model).Objects.Add(new Player(((Ground)Model), endPoint)
            {
                ID = groundIndex++,
                Thickness = ObjectThickness,
                Location = new Point()
                {
                    X = rnd.Next(1, ((Ground)Model).Width),
                    Y = rnd.Next(1, ((Ground)Model).Height)
                }
            });
            return ((Ground)Model).Players.Last();
        }

        void AddPower(PowerType pType)
        {
            ((Ground)Model).Objects.Add(new Power(((Ground)Model), pType)
            {
                ID = groundIndex++,
                Thickness = ObjectThickness,
                Location = new Point()
                {
                    X = rnd.Next(1, ((Ground)Model).Width),
                    Y = rnd.Next(1, ((Ground)Model).Height)
                }
            });
            //return ((Ground)PlayGround).Powers.Last();
        }

        void AddCoin()
        {
            ((Ground)Model).Objects.Add(new Coin(((Ground)Model), rnd.Next(1, 11))
            {
                ID = groundIndex++,
                Thickness = ObjectThickness,
                Location = new Point()
                {
                    X = rnd.Next(1, ((Ground)Model).Width),
                    Y = rnd.Next(1, ((Ground)Model).Height)
                }
            });
            //return ((Ground)PlayGround).Coins.Last();
        }

        void AddObstacle()
        {
            ((Ground)Model).Objects.Add(new Obstacle(((Ground)Model), rnd.Next(1, 11))
            {
                ID = groundIndex++,
                Thickness = ObjectThickness,
                Location = new Point()
                {
                    X = rnd.Next(1, ((Ground)Model).Width),
                    Y = rnd.Next(1, ((Ground)Model).Height)
                }
            });
        }

        void AddCompartment()
        {
            ((Ground)Model).Objects.Add(new Compartment(((Ground)Model))
            {
                ID = groundIndex++,
                Thickness = ObjectThickness,
                Location = new Point()
                {
                    X = rnd.Next(1, ((Ground)Model).Width),
                    Y = rnd.Next(1, ((Ground)Model).Height)
                }
            });
        }

        public override void ProcessPeriodicEvent()
        {
            int iRnd = rnd.Next(1, 5);
            switch (iRnd)
            {
                case 1:
                    this.AddPower(GetRandomPowerType());
                    break;
                case 2:
                    this.AddCoin();
                    break;
                case 3:
                    this.AddObstacle();
                    break;
                case 4:
                    this.AddCompartment();
                    break;
            }
        }

        public override void Update(string endPoint, DataPacketHeader header, object obj)
        {
            if (obj != null)
            {
                Player player = ((Ground)Model).Players.Find(p => p.EndPoint == endPoint);
                switch (header.Command)
                {
                    case "ChangeDirection":
                        player = (Player)obj;
                        break;
                    case "Collision":
                        try
                        {
                            if (player == null)
                                return;

                            int g = ((Ground)Model).Objects.FindIndex(go => go.ID == ((GroundObject)obj).ID);
                            if (g >= 0)
                            {
                                ((Ground)Model).Objects.RemoveAt(g);
                                ((Ground)Model).Objects.Insert(g, (GroundObject)obj);
                                ((GroundObject)obj).Merge(player);
                            }
                        }
                        catch (Exception exc)
                        {
                            Console.WriteLine(exc.Message);
                            throw;
                        }
                        break;
                    default:
                        base.Update(endPoint, header, obj);
                        break;
                }
            }
        }

        public override void Clear()
        {
            base.Clear();
            for (int i = 0; i < ((Ground)Model).Objects.Count; i++)
            {
                GroundObject go = (GroundObject)((Ground)Model).Objects[i];
                if (go.IsConsumed)
                    ((Ground)Model).Objects.Remove(go);
            }
        }
    }
}
